package com.hns.frame.dao;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import com.hns.frame.enumrate.MsgType;
import com.hns.frame.exception.BusinessException;
import com.hns.tool.pub.PubUtil;

/**
 * entity通用的 CURD 单表操作
 * @author:Fisher
 * @email:zhuangcaijin@126.com
 * @version Revision 2.0.0
 */
@Component
public class CommonEntityDao {

	@PersistenceContext  
	private EntityManager entityManager;
	
	/**
	 * 获取管理类进行更复杂操作,不建议使用
	 * @return
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public EntityManager getEntityManager() {
		return entityManager;
	}

	/**
	 * 保存实体
	 * @param entity   保存的实体
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public void save(Object entity) {
		entityManager.persist(entity);
	}
	
	/**
	 * 更新实体
	 * @param entity   要更新的实体
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public void update(Object entity) {
		entityManager.merge(entity);
    }
	
	/**
	 * 获取实体
     * @param id 实体id主键
     * @param clazz 实体类型
	 * @return 查询结果
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public <T> T find(Serializable id, Class<T> clazz) {
		return entityManager.find(clazz, id);
	}
	
	/**
	 * 获取全部实体
     * @param clazz 实体类型
	 * @return 结果集
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findAll(Class<T> clazz) {
        String className = clazz.getSimpleName();
        String jpql = "select o from " + className + " o ";
        return entityManager.createQuery(jpql).getResultList();
    }
	
	/**
	 * 删除实体
     * @param entity 需要删除的实体
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public void delete(Object entity) {
		entityManager.remove(entity);
	}
	
	/**
	 * 批量删除实体
     * @param clazz 实体类型
     * @param ids 要删除的实体主键
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public <T> void delete(Class<T> clazz, String[] ids) {
		for(String id: ids) {
			entityManager.remove(entityManager.getReference(clazz, id));
		}
	}
	
	/**
	 * 根据查询语句获取实体列表
     * @param jpql jpa查询语句，参数使用数字占位符
     * @param params 查询参数，依次序传入
	 * @return 查询列表
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	@SuppressWarnings("unchecked")
    public <T> List<T> findByJpql(String jpql, Object... params) {
        Query query = entityManager.createQuery(jpql);
        if (params != null) {
            for(int i = 0 ; i < params.length ; i ++){
                query.setParameter(1 + i, params[i]);
            }
        }
        
        return query.getResultList();
    }
	
	/**
	 * 根据查询语句获取Map列表
     * @param jpql jpa查询语句，参数使用数字占位符
     * @param params 查询参数，依次序传入
	 * @return 结果集的map
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	public Map<String, Map<String,Object>> findByJpqlForMap(String jpql,String[] fields,Object... params){
		Query query = entityManager.createQuery(jpql);
		if (params != null) {
		    for(int i = 0 ; i < params.length ; i ++){
		        query.setParameter(1 + i, params[i]);
		    }
		}
		
		List<Object[]> list = query.getResultList();
		if(PubUtil.isEmpty(list)){
			return null;
		}
		Map <String, Map<String,Object>> results = new HashMap<String, Map<String,Object>>();
		//记录遍历
		for (Object objects[] : list) {
			if(objects.length != fields.length){
				throw new BusinessException(MsgType.ERROR.getFlag(),"参数个数与返回数不一致！");
			}
			
			Map <String,Object>result = new HashMap<String,Object>();
			String key = null;
			//字段遍历
			for (int i = 0; i < objects.length; i++) {
				Object object = objects[i];
				result.put(fields[i], object);
				if(i == 0){
					key = object.toString();
				}
			} 
			results.put(key, result);
		}
		return results;
	}
	
	/**
	 * jpa翻页   不建议使用，统一使用mybatis
	 * @param jpql
	 * @param pageAlias
	 * @param pageable
	 * @param params
	 * @return 翻页对象
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	@SuppressWarnings("unchecked")
	public <T> Page<T> queryPageByJpql(String jpql, String pageAlias, Pageable pageable, Object... params){
		if (PubUtil.isEmpty(jpql))
			return null;
		
        //查询总页数
		int index = jpql.toLowerCase().indexOf("from");
		StringBuffer countSql = new StringBuffer("select count(").append(pageAlias).append(")");
		countSql.append(jpql.substring(index));
		Query query = entityManager.createQuery(countSql.toString());
        if (params != null) {
            for(int i = 0 ; i < params.length ; i ++){
                query.setParameter(1 + i, params[i]);
            }
        }
		
        long totalPage = (Long)query.getSingleResult();
        if (totalPage <=0)
        	return null;
       
        //查询分页记录
 		query = entityManager.createQuery(jpql);
        if (params != null) {
            for(int i = 0 ; i < params.length ; i ++){
                query.setParameter(1 + i, params[i]);
            }
        }
        
        List<T> list = query.setFirstResult(pageable.getOffset()).setMaxResults(pageable.getPageSize()).getResultList();

		Page<T> page = new PageImpl<T>(list, pageable, totalPage);
		return page;
	}
	
	/**
	 * 根据查询语句获取唯一实体
     * @param jpql jpa查询语句，参数使用数字占位符
     * @param params 查询参数，依次序传入
	 * @return 查询结果
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
	@SuppressWarnings("unchecked")
    public <T> T findOneByJpql(String jpql, Object... params) {
        Query query = entityManager.createQuery(jpql);
        if (params != null) {
            for(int i = 0 ; i < params.length ; i ++){
                query.setParameter(1 + i, params[i]);
            }
        }
        return (T) query.getSingleResult();
    }
	
	@SuppressWarnings("unchecked")
    public <T> T findOneByJpql(String jpql, Map<String, Object> params) {
        Query query = entityManager.createQuery(jpql);
        if (params != null) {
            Set<Entry<String,Object>> setEntry = params.entrySet();
            for (Entry<String, Object> entry : setEntry) {
                String key = entry.getKey();
                Object value = entry.getValue();
                query.setParameter(key, value);
            }
        }
        return (T) query.getSingleResult();
    }
    
	/**
	 * 执行sql更新
     * @param jpql jpa更新语句，参数使用数字占位符
     * @param params 条件参数，依次序传入
	 * @return 返回更新数量
	 * @author:Fisher
	 * @email:zhuangcaijin@126.com
	 */
    public int executeJpql(String jpql, Object...params) {
        Query query = entityManager.createQuery(jpql);
        if (params != null) {
            for(int i = 0 ; i < params.length ; i ++){
                query.setParameter(1 + i, params[i]);
            }
        }
        return query.executeUpdate();
    }
    
    /**
     * 强制立即更新数据库表   
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public void flush() {
    	entityManager.flush();
    }
    
    /**
     * 强制立即清空session缓存
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public void clear() {
    	entityManager.clear();
    }
    
    /**
     * 根据属性查询
     * @param clazz 类
     * @param fieldValues 参数
     * @return  结果列表
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    @SuppressWarnings({"unchecked", "rawtypes" })
	public <T> List<T> findByParamsIgnoreNullValue(Class<T> clazz, Map<String, Object> fieldValues) {
    	StringBuffer jpql = new StringBuffer("");
    	List params = new ArrayList();
    	
    	jpql.append(MessageFormat.format("SELECT entity FROM {0} entity WHERE 1 = 1  ", clazz.getName()));
    	if(fieldValues != null && fieldValues.size() > 0) {
    		Set<Entry<String, Object>> entrySet = fieldValues.entrySet();
    		for (Entry<String, Object> entry : entrySet) {
				if(entry != null && entry.getValue() != null) {
					jpql.append(MessageFormat.format(" AND {0} = {1} ", entry.getKey(), "?"));
					params.add(entry.getValue());
				}
			}
    	}
    	
    	Query query = entityManager.createQuery(jpql.toString());
    	
    	if (params != null && params.size() > 0) {
    		for(int i = 0 ; i < params.size() ; i ++){
    			query.setParameter(1 + i, params.get(i));
    		}
    	}
    	
    	return query.getResultList();
    }
    
    /**
     * 根据属性删除
     * @param clazz 类
     * @param fieldValues 参数
     * @return  删除数量
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    @SuppressWarnings({"unchecked", "rawtypes" })
    public <T> int deleteByParamsIgnoreNullValue(Class<T> clazz, Map<String, Object> fieldValues) {
        StringBuffer jpql = new StringBuffer("");
        List params = new ArrayList();
        
        jpql.append(MessageFormat.format("DELETE {0} entity WHERE 1 = 1  ", clazz.getName()));
        if(fieldValues != null && fieldValues.size() > 0) {
            Set<Entry<String, Object>> entrySet = fieldValues.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                if(entry != null && entry.getValue() != null) {
                    jpql.append(MessageFormat.format(" AND {0} = {1} ", entry.getKey(), "?"));
                    params.add(entry.getValue());
                }
            }
        }
        
        Query query = entityManager.createQuery(jpql.toString());
        
        if (params != null && params.size() > 0) {
            for(int i = 0 ; i < params.size() ; i ++){
                query.setParameter(1 + i, params.get(i));
            }
        }
        
        return query.executeUpdate();
    }
}
